// 正则表达式

// 创建正则表达式的两种方式
// 1. 正则字面量：用在正则规则非常清晰的情况下，正则的规则是静态的，无法更改
/\s+/g;
'于艺 于小艺 于大艺'.match(/于[\s\S]*?艺/g);
// ['于艺', '于小艺', '于大大大大大艺']
// 2. 正则对象：用在正则规则模糊的情况，也就是说，正则表达式中的规则是动态的定义的
new RegExp('\\' + 'w+');

// 字符串字面量
'12312321544132';
// 字符串对象
new String('12312541231');

const str = '简单模式是由你想直接找到的字符构成'
// 简单模式
str.match(/字符/);
// 特殊字符：比如：* 任意数量 ? 可能为空 [\s\S] 任意字符
'于艺 于小艺 于大艺'.match(/于[\s\S]*?艺/g);

'Bob'.match(/^B/) // startsWith
'Bob'.match(/b$/) // endsWith
"A ghost boooooed boooed booooooooooed".match(/bo*/g) // ['booooo', 'booo', 'boooooooooo']
'xxxx 于艺 xxx 于艺 xxx xxxx, 于艺'.match(/于艺+/g) // ['于艺', '于艺', '于艺']


// 正则表达式中的特殊字符
// \ 反斜杠
// 如果普通字母前不加 \
'abc'.match(/b/); // ['b']
// 如果普通字母前加了 \ 则代表转义字符
'abc'.match(/\b/); // ['b']

// 如果特殊字符前不加 \
"A ghost boooooed boooed booooooooooed".match(/bo*/g)
// 如果特殊字符前加了 \ 则代表普通字符
"A ghost b*****ed b***ed b******ed".match(/b\**/g)

// ^ 匹配字符串开头部分是否与规则相同
'Bob is good'.match(/^Bob/) // startsWith
// $ 匹配字符串结尾部分是否与规则相同
'Bob is good'.match(/good$/) // endsWith

// * 匹配前一个表达式0次或多次 等价于 {0,}
"A ghost bo boooed booooooooooed".match(/bo*/g)

// + 匹配前一个表达式1次或多次 {1,}
'xxxx 于艺 xxx 于艺 xxx xxxx, 于艺'.match(/于艺+/g) // ['于艺', '于艺', '于艺']

"A ghost b boooed booooooooooed".match(/bo*/g)
// ['b', 'booo', 'boooooooooo'] 这里 * 是指 b后面的o可以没有

"A ghost b boooed booooooooooed".match(/bo+/g)
// ['booo', 'boooooooooo'] 这里的 + 是指 b后面的o至少存在一个

// 表达式加上 ? 表示表达式只匹配0到1次
"A ghost b boooed booooooooooed".match(/bo+?/g)
// ['bo', 'bo'] 这里的 ? 会解除 + 原本的贪婪模式，使其只匹配 bo，不再匹配 bo 后面 o
"A ghost b boooed booooooooooed".match(/bo*?/g)
// ['b', 'b', 'b'] 这里的 ? 同样会接触 * 原本的贪婪模式，只匹配最小规则下的内容


if (match) {
    console.log("区号:", match[1]); // 输出: 区号: 123
    console.log("前缀:", match[2]); // 输出: 前缀: 456
    console.log("线路号:", match[3]); // 输出: 线路号: 7890
}

// \B 是指字母a不位于单词的边缘，也就是说a的左右都有单词
const regex = /\Ba\B/g;
const str2 = "A cat and a banana are in an area.";
str2.match(regex); // ['a', 'a', 'a'] c'a't b'a'n n'a'n

// \b
const regex = /t\b/g;
const str = "A cat and a banana are in an area.";
str.match(regex); // ['t'] cat 中的 t
const regex = /\bc/g;
const str = "A cat and a banana are in an area.";
str.match(regex); // ['c'] cat 中的 c

// ---------------------------------- 基础类型 -----------------------------------------------

// \d 匹配数字
// \d{3,11} 匹配3到11位连续的数字
// \D 匹配非数字字符
"B2 is the suite number.".match(/\D/g)
// ['B', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 's', 'u', 'i', 't', 'e', ' ', 'n', 'u', 'm', 'b', 'e', 'r', '.'] 只把2去掉了

// \f 换页符
// \n 换行符
// \r 回车符
// \t tab 水平制表符（制表符：制作表格的字符）
// \v 垂直制表符

// \s 空白字符 [\f\n\r\t\v\u0020\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。
// \S 非空白字符 等价于 [^\f\n\r\t\v\u0020\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。

// \w 匹配字母、数字、下划线 等价于 [A-Za-z0-9_]
// \W 匹配非字母、数字、下划线 等价于 [^A-Za-z0-9_]

// \0 匹配null字符
// \xhh 匹配16进制的 uft-16字符
// \uhhhh 匹配 uft-16字符
// \u{hhhh} 或 \u{hhhhh} 匹配 unicode 字符

// ---------------------------------- 操作符 -------------------------------------------

// \d{3} =等价于=> \d\d\d {3}前的规则会重复3次
// \d{3,} \d规则至少会重复3次
// \d{1,3} \d规则最多会重复1-3次（大于等于1次，小于等于3次）
'333 33 333333'.match(/(\d{3,})/)

// () 匹配一组连贯的规则
// () 分组的含意是，()内部的正则表达式是一组连贯的规则
const regex = /\((\d{3})\) (\d{3})-(\d{4})/;
const str1 = "(123) 456-7890";
const match = str1.match(regex);

// 字符集合 []
// [] 匹配一组非连贯的规则 对于字母或数字，可以采用 开头-结尾 的形式，匹配一个范围
'abcdefghijklmnopqrstuvwxyz0123456789'.match(/[r-t]/g) // ['r', 's', 't']
'abcdefghijklmnopqrstuvwxyz0123456789'.match(/[0-5]/g) // ['0', '1', '2', '3', '4', '5'] // 电话号码

'_@!#!@%$***$!@#!@$_'.match(/[*]/g) // ['*', '*', '*']
// 反向字符集合
// [^规则] 代表将规则进行取反操作，也就是只要不与规则相匹配的都会进行匹配
'_@!#!@%$***$!@#!@$_'.match(/[^*]/g) // ['_', '@', '!', '#', '!', '@', '%', '$', '$', '!', '@', '#', '!', '@', '$', '_']
// \d：等价于 [0-9]，匹配一个数字字符。
// \D：等价于 [^0-9]，匹配一个非数字字符。
// \w：等价于 [A-Za-z0-9_]，匹配一个字母、数字或下划线字符。
// \W：等价于 [^A-Za-z0-9_]，匹配一个非字母、非数字且非下划线字符。

// () [] {}
// () 1.用来分组 2.组内规则是连贯的
// [] 1.用来匹配非连贯的规则 2.a-z A-Z 0-9 可以用-确定一个范围 3. ^ 用来取反
// {} 1.{n} 前面规则重复n次 2.{n,} 前面的规则至少重复n次 3. {n,m} 前面规则重复 n-m 次

// . 匹配代表除了换行符 \n 之外的任意单个字符

// ---------------------------------- 高阶操作符 -------------------------------------------
let html = '<body> <div> <p>123</p> </div> </body>'
// <(\/?)(?:\w+)>
// < ... > 普通字符
// (/?) 分组 / 可有 可无
// (?:\w+)
'<body> <div class="main"> <p>123</p> </div> </body>'.match(/<(\/?)(?:\w+)>/g)
// ['<body>', '<p>', '</p>', '</div>', '</body>']0: "<body>"1: "<p>"2: "</p>"3: "</div>"4: "</body>"length: 5[[Prototype]]: Array(0)
'<body> <div class="main"> <p>123</p> </div> </body>'.match(/<(\/?)(?:[\s\S]*?)>/g)
// ['<body>', '<div class="main">', '<p>', '</p>', '</div>', '</body>']

// (?:规则){1,2} 让规则作为一个整体参与到后面表达式运算中
// /<(?:[\w\W]*?)>/g (?: [\w\W]*? )

// 先行断言 (更多的不是用来搜索，而是用来判断是否存在)
// 先行(?=断言)
// 1.先行：前面部分是提前确定的
// 2.断言：后面部分一定是与规则相匹配的
// JackSprat => /Jack(?=Sprat)/ Jack 后面断定是 Sprat
// JackSprat JackFrost => /Jack(?=Sprat|Frost)/ Jack 后面断定是 Sprat 或 Frost

// 后行断言
// (?<=断言)后行
// 1.断言：前面部分一定是与规则想匹配的
// 2.后行：后面部分是提前确定的
// JackSprat => /(?<=Jack)Sprat/ Sprat 前面断定是 Jack
// JackSprat FrostSprat => /(?<=Jack|Frost)Sprat/ Sprat 前面断定是 Jack 或 Frost

// 正向否定查找 (先行否定查找)
'JackFrost JackTom JackSprat'.match(/Jack(?!Sprat)(\w*)/g) // ['JackFrost', 'JackTom']

// 反向否定查找 (后行否定查找)
'JackFrost TomFrost SpratFrost'.match(/(\w*)(?<!Tom)Frost/g) // ['JackFrost', 'SpratFrost']

// '代码文本'.replace(/Forst/g, 'Frost')

// 或 |
// /x|y/ 可以是x也可以是y
'abcdxyz'.match(/x|y/g); // ['x', 'y']

// 控制符
// \cA-Z 是指 control + A-Z

// --------------- 标识符 ----------------------
/\d+/g // 全局搜索
/\w+/i // 不区分大小写进行搜索
/\w+/m // 多行搜索。
/\w+/s // 允许 . 匹配换行符。
/\w+/u // 使用 unicode 码的模式进行匹配。
/\w+/y // 执行“粘性 (sticky)”搜索，匹配从目标字符串的当前位置开始。
/zxasdasZDSAXZCasdas/gi // 标识符可以组合

// (?:) \d{3} 000 111 | \(\d{3}\) (000) (111)
// ([-\/\.])

// 正则语法 正则语言

// 作业1：正则相关内容，在复习一遍，加深印象

// 1. 基础类型
/\d/ // 数字
/\D/ // 非数字
/\b/ // 单词边缘
/\B/ // 单词内部
/\s/ // 空白字符
/\S/ // 非空白字符
/\w/ // 字母数字下划线
/\W/ // 非字母数字下划线

/\f/ // 换页符
/\n/ // 换行
/\r/ // 回车
/\v/ // 垂直制表符

/\0/ // 空白字符
/\x00/ // 2位16进制数表示的字符
/\u0000/ // 4位16进制数表示的字符

// 2. 运算符
/(...)/ // 1.分组 2.组内连贯
/[...]/ // 1.非连贯规则 2.a-h 可以用 - 前后确定一个范围，字母，数字。 3. ^ 取反 [\s\S]
/\d{0,1}/ // 1.{n} 前面的表达式重复n次。 2.{n,} 前面的表达式至少重复n次 3.{n,m} n <= 表达式重复次数 <= m

// 3. 高阶操作符-公式
/(?:x\d){1,2}/ // 冒号后的规则取整

/str(?=ing|ed)/ // 先行断言
/(?<=str|eat|walk|sleep)ing/ // 后行断言

/str(?!ing)/ // 先行否定查找
/(?<!str)ing/ // 后行否定查找

/\cX/ // control + X 控制符

/.../ // . 代表非空白字符

// 作业2：预习数组方法相关内容
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Indexed_collections#%E5%88%9B%E5%BB%BA%E6%95%B0%E7%BB%84

// API => App Protocol Interface // 应用协议接口
// 接口？接口就是类提供给外部使用的公共函数（广义）
''.replaceAll(); // 公共函数
''.match(); // 公共函数

 // class Interface {
 //     public a;
 //     protected b;
 //     private c;
 // }

